/*
 * DevicesLed.c
 *
 *      Author: Honrun
 */

#include "gd32w51x.h"
#include "DevicesSoftTimer.h"
#include "DevicesLed.h"





static void vLedPWMInit(void);


static LedInfoType st_typeLedInfo = {0};

/* 周期调用计数（调用频率为10k） */
volatile static uint32_t st_uiLedTickCnt = 0;
/* 呼吸档位 */
volatile static int16_t st_sGrade = 0;
/* 呼吸方向 */
volatile static int8_t st_cDirection = 0;


SoftTimerTypeDef g_typeSoftTimerLedHanle = {0};


void vSoftTimerLedCallbackFunction(void *pvHandle)
{
    (void)pvHandle;

    vLedMachine();
}

void vLedInit(void)
{
    /* enable the LED GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_GPIOC);

    /* configure LED GPIO pin */
    gpio_mode_set(LED_WHITE_GPIO_Port, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED_WHITE_Pin);
    gpio_output_options_set(LED_WHITE_GPIO_Port, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, LED_WHITE_Pin);

    gpio_mode_set(LED_YELLOW_GPIO_Port, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED_YELLOW_Pin);
    gpio_output_options_set(LED_YELLOW_GPIO_Port, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, LED_YELLOW_Pin);

    gpio_mode_set(LED_GREEN_GPIO_Port, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED_GREEN_Pin);
    gpio_output_options_set(LED_GREEN_GPIO_Port, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, LED_GREEN_Pin);

    gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_3);
    gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_3);

    gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_4);
    gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_4);

    vLedOpen(LED_ALL);


    st_typeLedInfo.white.periph = LED_WHITE_GPIO_Port;
    st_typeLedInfo.white.pin = LED_WHITE_Pin;

    st_typeLedInfo.yellow.periph = LED_YELLOW_GPIO_Port;
    st_typeLedInfo.yellow.pin = LED_YELLOW_Pin;

    st_typeLedInfo.green.periph = LED_GREEN_GPIO_Port;
    st_typeLedInfo.green.pin = LED_GREEN_Pin;

    st_typeLedInfo.green.timerPeriph = TIMER0;
    st_typeLedInfo.green.channel = TIMER_CH_1;
    vLedPWMInit();


    /* 软件定时器周期调用 */
    cSoftTimerCreateMs(&g_typeSoftTimerLedHanle, 10, softTimerOpen | softTimerCircular, vSoftTimerLedCallbackFunction);

    vLedSetStatus(LED_ALL, LED_FLASH_SLOW, 10);
}

static void vLedPWMInit(void)
{
    timer_oc_parameter_struct timer_ocintpara = {0};
    timer_parameter_struct timer_initpara = {0};

    rcu_periph_clock_enable(RCU_TIMER0);

    gpio_mode_set(LED_GREEN_GPIO_Port, GPIO_MODE_AF, GPIO_PUPD_PULLUP, LED_GREEN_Pin);
    gpio_output_options_set(LED_GREEN_GPIO_Port, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, LED_GREEN_Pin);
    gpio_af_set(LED_GREEN_GPIO_Port, GPIO_AF_8, LED_GREEN_Pin);

    timer_deinit(TIMER0);

    /* TIMER configuration */
    timer_initpara.prescaler         = 1 - 1;
    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection  = TIMER_COUNTER_UP;
    timer_initpara.period            = (SystemCoreClock / 10000) - 1;
    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
    timer_initpara.repetitioncounter = 0;
    timer_init(TIMER0, &timer_initpara);

    timer_ocintpara.outputstate  = TIMER_CCX_ENABLE;
    timer_ocintpara.outputnstate = TIMER_CCXN_DISABLE;
    timer_ocintpara.ocpolarity   = TIMER_OC_POLARITY_LOW;
    timer_ocintpara.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;
    timer_ocintpara.ocidlestate  = TIMER_OC_IDLE_STATE_HIGH;
    timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
    timer_channel_output_config(TIMER0, TIMER_CH_1, &timer_ocintpara);

    /* CH0 configuration in PWM mode0,duty cycle 25% */
    timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_1, TIMER_CAR(TIMER0) / 2);
    timer_channel_output_mode_config(TIMER0, TIMER_CH_1, TIMER_OC_MODE_PWM0);
    timer_channel_output_shadow_config(TIMER0, TIMER_CH_1, TIMER_OC_SHADOW_DISABLE);

    timer_primary_output_config(TIMER0, ENABLE);
    /* auto-reload preload enable */
    timer_auto_reload_shadow_enable(TIMER0);
    /* enable a TIMER */
    timer_enable(TIMER0);
}

void vLedOpen(uint16_t usChannel)
{
    if(usChannel & LED_WHITE)
        gpio_bit_set(LED_WHITE_GPIO_Port, LED_WHITE_Pin);
    if(usChannel & LED_YELLOW)
        gpio_bit_set(LED_YELLOW_GPIO_Port, LED_YELLOW_Pin);
    if(usChannel & LED_GREEN)
        gpio_bit_set(LED_GREEN_GPIO_Port, LED_GREEN_Pin);
}

void vLedClose(uint16_t usChannel)
{
    if(usChannel & LED_WHITE)
        gpio_bit_reset(LED_WHITE_GPIO_Port, LED_WHITE_Pin);
    if(usChannel & LED_YELLOW)
        gpio_bit_reset(LED_YELLOW_GPIO_Port, LED_YELLOW_Pin);
    if(usChannel & LED_GREEN)
        gpio_bit_reset(LED_GREEN_GPIO_Port, LED_GREEN_Pin);
}

void vLedRevesal(uint16_t usChannel)
{
    if(usChannel & LED_WHITE)
        gpio_bit_toggle(LED_WHITE_GPIO_Port, LED_WHITE_Pin);
    if(usChannel & LED_YELLOW)
        gpio_bit_toggle(LED_YELLOW_GPIO_Port, LED_YELLOW_Pin);
    if(usChannel & LED_GREEN)
        gpio_bit_toggle(LED_GREEN_GPIO_Port, LED_GREEN_Pin);
}

/*
 * Return:      void
 * Parameters:  usChannel: LED通道; usChannel: 状态; usChannel: 闪烁次数/或者占空比;
 * Description: 设置LED状态
 */
void vLedSetStatus(uint16_t usChannel, LedStateEnum enumStatus, uint8_t ucFlashCnt_or_Duty)
{
    if(usChannel & LED_YELLOW)
    {
        st_typeLedInfo.yellow.state = enumStatus;
        st_typeLedInfo.yellow.flashCnt = ucFlashCnt_or_Duty * 2 + 1;
        st_typeLedInfo.yellow.duty = ucFlashCnt_or_Duty % 101;
    }
    if(usChannel & LED_WHITE)
    {
        st_typeLedInfo.white.state = enumStatus;
        st_typeLedInfo.white.flashCnt = ucFlashCnt_or_Duty * 2 + 1;
        st_typeLedInfo.white.duty = ucFlashCnt_or_Duty % 101;
    }
    if(usChannel & LED_GREEN)
    {
        st_typeLedInfo.green.state = enumStatus;
        st_typeLedInfo.green.flashCnt = ucFlashCnt_or_Duty * 2 + 1;
        st_typeLedInfo.green.duty = ucFlashCnt_or_Duty % 101;
    }
}

/*
 * Return:      void
 * Parameters:  *ptypeLed: LED信息结构体
 * Description: LED状态刷新
 */
void vLedStateMachine(LedType *ptypeLed)
{
    switch(ptypeLed->state)
    {
        /* 关闭 */
        case LED_DISABLE:
            (ptypeLed->timerPeriph == 0) ? \
            (GPIO_BC(ptypeLed->periph) = ptypeLed->pin) : \
            timer_channel_output_pulse_value_config(ptypeLed->timerPeriph, ptypeLed->channel, 0);
            ptypeLed->state = LED_IDLE;
            break;

        /* 常亮 */
        case LED_ENABLE:
            (ptypeLed->timerPeriph == 0) ? \
            (GPIO_BOP(ptypeLed->periph) = ptypeLed->pin) : \
            timer_channel_output_pulse_value_config(ptypeLed->timerPeriph, ptypeLed->channel, TIMER_CAR(ptypeLed->timerPeriph));
            ptypeLed->state = LED_IDLE;
            break;

        /* 呼吸 */
        case LED_BREATHE:
            if(ptypeLed->timerPeriph != 0)
                timer_channel_output_pulse_value_config(ptypeLed->timerPeriph, ptypeLed->channel, TIMER_CAR(ptypeLed->timerPeriph) * st_sGrade / 127);
            break;

        /* 固定占空比 */
        case LED_DUTY:
            if(ptypeLed->timerPeriph != 0)
                timer_channel_output_pulse_value_config(ptypeLed->timerPeriph, ptypeLed->channel, (TIMER_CAR(ptypeLed->timerPeriph) * (100 - ptypeLed->duty)) / 100);
            ptypeLed->state = LED_IDLE;
            break;

        /* 快闪/快闪后关闭/快闪后常亮 */
        case LED_FLASH_SLOW:
        case LED_FLASH_SLOW_DISABLE_CNT:
        case LED_FLASH_SLOW_ENABLE_CNT:
            if((st_uiLedTickCnt % 100) == 0)
            {
                (ptypeLed->timerPeriph == 0) ? \
                (GPIO_TG(ptypeLed->periph) = ptypeLed->pin) : \
                timer_channel_output_pulse_value_config(ptypeLed->timerPeriph, ptypeLed->channel, ((st_uiLedTickCnt / 100) & 1) ? TIMER_CAR(ptypeLed->timerPeriph) : 0);

                if((ptypeLed->state != LED_FLASH_SLOW) && ((ptypeLed->flashCnt--) <= 0))
                {
                    ptypeLed->state = (ptypeLed->state == LED_FLASH_SLOW_ENABLE_CNT) ? LED_ENABLE : LED_DISABLE;
                }
            }
            break;

        /* 慢闪/慢闪后关闭/慢闪后常亮 */
        case LED_FLASH_FAST:
        case LED_FLASH_FAST_DISABLE_CNT:
        case LED_FLASH_FAST_ENABLE_CNT:
            if((st_uiLedTickCnt % 50) == 0)
            {
                (ptypeLed->timerPeriph == 0) ? \
                (GPIO_TG(ptypeLed->periph) = ptypeLed->pin) : \
                timer_channel_output_pulse_value_config(ptypeLed->timerPeriph, ptypeLed->channel, ((st_uiLedTickCnt / 50) & 1) ? TIMER_CAR(ptypeLed->timerPeriph) : 0);

                if((ptypeLed->state != LED_FLASH_FAST) && ((ptypeLed->flashCnt--) <= 0))
                {
                    ptypeLed->state = (ptypeLed->state == LED_FLASH_FAST_ENABLE_CNT) ? LED_ENABLE : LED_DISABLE;
                }
            }
            break;

        default : break;
    }
}

/*
 * Return:      void
 * Parameters:  void
 * Description: LED心跳计数 + 呼吸状态机
 */
static void vLedIncTick(void)
{
    /* 所有LED使用同一个状态机变量，以方便实现一致的闪烁步调 */
    ++st_uiLedTickCnt;

    /* 更新呼吸模式占空比 */
    {
        st_sGrade += st_cDirection;
        /* 之所以把档位设置的比127大一点，是为了在呼吸状态时，LED能够彻底熄灭一段时间 */
        st_cDirection = (st_sGrade >= 150) ? -1 : ((st_sGrade <= 0) ? 1 : st_cDirection);
    }
}

void vLedMachine(void)
{
    vLedIncTick();

    vLedStateMachine(&st_typeLedInfo.white);

    vLedStateMachine(&st_typeLedInfo.yellow);

    vLedStateMachine(&st_typeLedInfo.green);
}

LedInfoType *ptypeLedGetInfo(void)
{
    return &st_typeLedInfo;
}
